package services

import (
	"encoding/json"
	"fmt"
	"go.uber.org/zap"
	"io/ioutil"
	"net/http"
	"net/url"
	"purchase-mall/dao/redis"
	"purchase-mall/models"
	"purchase-mall/utils"
	"strconv"
	"strings"
	"sync"
	"time"
)

//GetPeakValueService 近三天请求峰值
func GetPeakValueService() (peakValueInfos []*models.PeakValueInfo, err error) {
	var timesMap = map[int][]int64{
		1: []int64{utils.RandomTime(-2), utils.RandomTime(-1)},
		2: []int64{utils.RandomTime(-1), utils.YesterdayTime()},
		3: []int64{utils.YesterdayTime(), utils.TodayTime()},
	}

	peakValueInfos = make([]*models.PeakValueInfo, 0, len(timesMap))

	//redis查1,2数据
	ts1 := time.Now().AddDate(0, 0, -2)
	ts2 := time.Now().AddDate(0, 0, -1)
	time1 := ts1.Format("2006-01-02")
	time2 := ts2.Format("2006-01-02")
	err1, va1 := redis.GetPeakValue(time1)
	if err1 == nil {
		var peakValue = models.PeakValueInfo{
			Time: time1,
		}
		va1s := strings.Split(va1, "+")
		if va1s != nil && len(va1s) == 2 {
			peakValue.FiveTime = va1s[0]
			pv1, err11 := strconv.Atoi(va1s[1])
			if err11 == nil {
				peakValue.PeakValue = int64(pv1)
			}

		}
		peakValueInfos = append(peakValueInfos, &peakValue)
	}
	err2, va2 := redis.GetPeakValue(time2)
	if err2 == nil {
		var peakValue = models.PeakValueInfo{
			Time: time2,
		}
		va2s := strings.Split(va2, "+")
		if va2s != nil && len(va2s) == 2 {
			peakValue.FiveTime = va2s[0]
			pv2, err22 := strconv.Atoi(va2s[1])
			if err22 == nil {
				peakValue.PeakValue = int64(pv2)
			}

		}
		peakValueInfos = append(peakValueInfos, &peakValue)
	}

	var wg sync.WaitGroup
	wg.Add(3 - len(peakValueInfos))

	var fiveValues = make([]*models.FiveValues, 0, 3-len(peakValueInfos))
	if len(peakValueInfos) == 2 {
		delete(timesMap, 1)
		delete(timesMap, 2)
	}
	for k, _ := range timesMap {
		go func(k int) {
			defer wg.Done()

			params := url.Values{}
			parseURL, err := url.Parse(utils.PeakValueUrl)
			if err != nil {
				return
			}
			params.Set("query", fmt.Sprintf("sum(count_over_time({filename=\"/apisix/log/error.log\",from=\"access log\",env=\"prod\",exporter=\"promtail\"} [5m]))"))
			startTime := timesMap[k][0] + 300000000000
			params.Set("start", strconv.FormatInt(startTime, 10))
			params.Set("end", strconv.FormatInt(timesMap[k][1], 10))
			params.Set("step", "300")
			parseURL.RawQuery = params.Encode()
			urlPathWithParams := parseURL.String()

			client := http.Client{
				Timeout: 10 * time.Minute,
			}
			resp, err := client.Get(urlPathWithParams)
			if err != nil {
				zap.L().Error("Loki Http Api GetPeakValueService failed",
					zap.Int64("start", startTime),
					zap.Int64("end", timesMap[k][1]),
					zap.Error(err))
				return
			}
			defer resp.Body.Close()

			body, err := ioutil.ReadAll(resp.Body)

			if err != nil {
				return
			}
			var res RespJsons
			err = json.Unmarshal(body, &res)
			if err != nil {
				return
			}

			if res.Status != "success" {
				return
			}

			var fiveValue = new(models.FiveValues)
			var values = make([]*models.Values, 0)
			var requestNum, fiveT int
			if res.Data.Result != nil && len(res.Data.Result) > 0 {
				if res.Data.Result[0].Values != nil && len(res.Data.Result[0].Values) >= 2 {
					for _, v := range res.Data.Result[0].Values {
						fiveT = int(v[0].(float64))
						requestNum, _ = strconv.Atoi(v[1].(string))

						var value = models.Values{
							Time:  time.Unix(int64(fiveT), 0).Format("2006-01-02 15:04:05"),
							Value: int64(requestNum),
						}

						values = append(values, &value)
					}
				}
			}
			switch k {
			case 1: //前天
				fiveValue.TimeType = 1
			case 2: //昨天
				fiveValue.TimeType = 2
			case 3: //今天
				fiveValue.TimeType = 3
			}

			fiveValue.Values = values
			fiveValues = append(fiveValues, fiveValue)
		}(k)
	}
	wg.Wait()

	//数据处理
	for _, v := range fiveValues {
		var peakValueInfo = new(models.PeakValueInfo)
		switch v.TimeType {
		case 1:
			ts := time.Now().AddDate(0, 0, -2)
			peakValueInfo.Time = ts.Format("2006-01-02")
		case 2:
			ts := time.Now().AddDate(0, 0, -1)
			peakValueInfo.Time = ts.Format("2006-01-02")
		case 3:
			peakValueInfo.Time = time.Now().Format("2006-01-02")
		}

		var max int64
		var fiveTime string
		if v.Values != nil && len(v.Values) > 0 {
			for _, value := range v.Values {
				if value.Value > max {
					max = value.Value
					fiveTime = value.Time
				}
			}
		}
		peakValueInfo.PeakValue = max
		peakValueInfo.FiveTime = fiveTime

		peakValueInfos = append(peakValueInfos, peakValueInfo)

		//存redis
		if v.TimeType == 1 || v.TimeType == 2 {
			value := fmt.Sprintf("%s+%d", fiveTime, max)
			redis.SetPeakValue(peakValueInfo.Time, value)
		}
	}

	BubbleSortPeak(peakValueInfos)

	return
}
